﻿using System;

namespace MathService
{
    public class LamdaStateMashine<TState, TValue>
    {
        public delegate TState Rule(TState State, TValue Value);

        public class NewValueEventArgs : EventArgs
        {
            public TState State { get; set; }
            public TValue Value { get; private set; }
            public NewValueEventArgs(TState State, TValue Value)
            {
                this.State = State;
                this.Value = Value;
            }
        }

        public class NewStateEventArgs : EventArgs
        {
            public TState OldState { get; private set; }
            public TState NewState { get; private set; }
            public TValue Value { get; private set; }
            public NewStateEventArgs(TState OldState, TState NewState, TValue Value)
            {
                this.OldState = OldState;
                this.NewState = NewState;
                this.Value = Value;
            }
        }

        public event EventHandler<NewValueEventArgs> NewValue;
        public event EventHandler<NewStateEventArgs> NewState;

        protected virtual TState OnNewValue(TValue Value)
        {
            var lv_NewValueEventArgs = new NewValueEventArgs(f_State, Value);
            OnNewValue(lv_NewValueEventArgs);
            return lv_NewValueEventArgs.State;
        }

        protected virtual void OnNewValue(NewValueEventArgs lv_NewValueEventArgs)
        {
            var handlers = NewValue;
            if(handlers != null)
                handlers(this, lv_NewValueEventArgs);
        }

        protected virtual void OnNewState(TState OldState, TState NewState, TValue Value = default(TValue))
        {

            var handlers = this.NewState;
            if(handlers != null) handlers(this, new NewStateEventArgs(OldState, NewState, Value));
        }

        private TState f_State;

        public TState State
        {
            get { return f_State; }
            set
            {
                if(f_State.Equals(value)) return;
                OnNewState(f_State, f_State = value);
            }
        }

        public LamdaStateMashine(TState State = default(TState)) { f_State = State; }

        public void Add(TValue Value)
        {
            var NewState = OnNewValue(Value);
            if(NewState.Equals(f_State)) return;
            OnNewState(f_State, f_State = NewState, Value);
        }
    }
}
